package org.jsola.hr.service.impl;

import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.jsola.common.DateKit8;
import org.jsola.common.PageKit;
import org.jsola.core.Page;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.DateUtils;
import org.jsola.hr.common.HrLogKit;
import org.jsola.hr.constant.*;
import org.jsola.hr.dao.IEmpSocInfoDAO;
import org.jsola.hr.dao.IEmpSocMonthDAO;
import org.jsola.hr.dao.IEmpSocPlanDAO;
import org.jsola.hr.dto.*;
import org.jsola.hr.entity.*;
import org.jsola.hr.provider.ISiteConfigProviderService;
import org.jsola.hr.query.EmpSocInfoQuery;
import org.jsola.hr.query.IncreaseDecreaseQuery;
import org.jsola.hr.service.*;
import org.jsola.hr.service.notice.ISendNoticeService;
import org.jsola.hr.vo.*;
import org.jsola.user.core.TokenUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static org.jsola.hr.constant.EmpSocConstant.NEED_CONFIRM;
import static org.jsola.hr.constant.EmpSocConstant.NO_CONFIRM;
import static org.jsola.hr.constant.EmpSocStatus.*;
import static org.jsola.hr.constant.EmpSocStatus.ATTRITION;
import static org.jsola.hr.constant.HrConstants.*;
import static org.jsola.hr.constant.HrConstants.PF_ITEM_TYPE;

/**
 * 员工参保信息附加表
 *
 * @author zhr
 */
@Slf4j
@Service("hrEmpSocInfoExtraServiceImpl")
public class EmpSocInfoExtraServiceImpl implements IEmpSocInfoExtraService {

    @Autowired
    private ISiteConfigProviderService siteConfigProviderService;

    @Autowired
    private IEmpSocRelatedService empSocRelatedService;

    @Autowired
    private IEmpSocInfoService empSocInfoService;

    @Autowired
    @Lazy
    private IEmpSocPlanService empSocPlanService;

    @Autowired
    @Lazy
    private IEmpSocPlanItemService empSocPlanItemService;

    @Autowired
    private ICostBillService costBillService;

    @Autowired
    private ISendNoticeService sendNoticeService;

    @Autowired
    private ISocProgService socSchemeService;

    @Autowired
    private ISocProgItemService socSchemeItemService;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IEmpSocMonthService empSocMonthService;

    @Autowired
    private IEmpSocTransformService empSocTransformService;

    @Autowired
    private IPersonalEventService personalEventService;

    @Autowired
    private IEmpSocMonthDAO empSocMonthDAO;

    @Autowired
    private IEmpSocPlanDAO empSocPlanDAO;

    @Autowired
    private ITreatmentDisposeEventService treatmentDisposeEventService;

    @Autowired
    private ISocPlanFeedbackRecordService socPlanFeedbackRecordService;

    @Autowired
    private ISocDifferenceService socDifferenceService;

    @Autowired
    private IEmpSocItemService empSocItemService;

    @Override
    public String getConfirmSocBySite(TokenUser tokenUser) {
        String confirmSoc = siteConfigProviderService.selectValueByCode("confirmSoc", tokenUser.getSiteId());
        if (StringUtils.isEmpty(confirmSoc)) {
            confirmSoc = NO_CONFIRM;
        }
        return confirmSoc;
    }

    @Override
    public String getAnnexVerifyBySite(TokenUser tokenUser) {
        String annexVerify = siteConfigProviderService.selectValueByCode("annexVerify", tokenUser.getSiteId());
        if (StringUtils.isEmpty(annexVerify)) {
            annexVerify = NO_CONFIRM;
        }
        return annexVerify;
    }

    @Override
    public String getRemarkVerifyBySite(TokenUser tokenUser) {
        String remarkVerify = siteConfigProviderService.selectValueByCode("remarkVerify", tokenUser.getSiteId());
        if (StringUtils.isEmpty(remarkVerify)) {
            remarkVerify = NO_CONFIRM;
        }
        return remarkVerify;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void cancelDecrease(String planId, TokenUser tokenUser) {
        // 把这条计划改为取消状态,置空对应的计划减员时间
        EmpSocPlanDO empSocPlan = empSocPlanService.selectDOById(planId, tokenUser.getSiteId());
        EmpSocRelatedDO empSocRelated = empSocRelatedService
                .selectByEmpId(empSocPlan.getEmpId(), tokenUser.getSiteId());
        // 更新取消状态
        empSocPlan.setFeedbackFlag(SocFeedbackFlag.CANCEL);
        empSocPlanService.updateByIdSelective(empSocPlan);
        // 置空计划减员时间
        Integer planType = empSocPlan.getType();
        empSocRelatedService.clearedPlanDecreaseDate(empSocRelated, planType, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void cancelIncrement(String planId, TokenUser tokenUser) {
        // 把这条计划改为取消状态,置空对应的计划增员时间
        EmpSocPlanDO empSocPlan = empSocPlanService.selectDOById(planId, tokenUser.getSiteId());
        EmpSocRelatedDO empSocRelated = empSocRelatedService
                .selectByEmpId(empSocPlan.getEmpId(), tokenUser.getSiteId());
        // 更新取消状态
        empSocPlan.setFeedbackFlag(SocFeedbackFlag.CANCEL);
        empSocPlanService.updateByIdSelective(empSocPlan);
        // 置空计划增员时间
        Integer planType = empSocPlan.getType();
        empSocRelatedService.clearedPlanIncreaseDate(empSocRelated, planType, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public String increaseExtra(EmpSocPlanBatchAddDTO batchIncreaseDTO, TokenUser tokenUser) {
        ParamException.notEmpty(batchIncreaseDTO.getEmpSocPlanAddDTOList(), "请选择参保人员");
        String companyId = batchIncreaseDTO.getCompanyId();
        String year = batchIncreaseDTO.getYear();
        String month = batchIncreaseDTO.getMonth();
        SocProgDO socProgDO = socSchemeService.selectDOById(batchIncreaseDTO.getSchemeId(), tokenUser.getSiteId());
        EmpSocPlanBatchAddDTO batchAddDTO = empSocPlanService.batchCalculationAmount(batchIncreaseDTO, socProgDO);
        // 增员列表
        List<EmpSocPlanAddDTO> empSocPlanAddDTOList = batchAddDTO.getEmpSocPlanAddDTOList();
        List<String> empIdList = empSocPlanAddDTOList.stream()
                .map(EmpSocPlanAddDTO::getEmpId).distinct().collect(Collectors.toList());
        // 查询这些员工的社保相关信息和花名册相关信息
        List<EmpSocRelatedDO> empSocRelatedList = empSocRelatedService
                .selectByEmpIdList(empIdList, tokenUser.getSiteId());
        Map<String, EmpSocRelatedDO> empSocRelatedMap = empSocRelatedList.stream()
                .collect(Collectors.toMap(EmpSocRelatedDO::getEmpId, v -> v));
        List<EmpInfoDO> empInfoDOList = empInfoService.selectDoByIds(empIdList);
        Date increaseDate = DateKit8.parse(year + "-" + month + "-01", "yyyy-MM-dd");
        // 判断一下是不是待增
        boolean plan = !CollectionUtils.isEmpty(DateUtils.getMonthDifferences(new Date(), increaseDate));
        EmpSocMonthDO empSocMonth = empSocMonthService
                .selectMonthByYearAndMonth(companyId, year, month, tokenUser.getSiteId());
        if (!ObjectUtils.isEmpty(empSocMonth)) {
            if (costBillService.checkMonthIdCreateCostBill(empSocMonth.getId(), tokenUser.getSiteId())) {
                throw new ParamException(month + "已创建账单不可进行增员操作");
            }
        }
        Map<String, EmpInfoDO> empInfoMap = empInfoDOList.stream().collect(Collectors.toMap(EmpInfoDO::getId, v -> v));
        // 校验重复增员
        checkRepeatIncrease(empSocRelatedMap, empInfoMap, empSocPlanAddDTOList);
        // 记录一下增员的人数,第一个人的姓名和员工Id,便于后面记录日志
        int saveCount = (int) empSocPlanAddDTOList.stream().map(EmpSocPlanAddDTO::getEmpId).distinct().count();
        String empName = empInfoDOList.get(0).getName();
        String empId = empInfoDOList.get(0).getId();
        List<EmpSocRelatedDO> updateList = new ArrayList<>();
        for (EmpSocPlanAddDTO empSocPlanAddDTO : empSocPlanAddDTOList) {
            EmpSocRelatedDO empSocRelatedDO = empSocRelatedMap.get(empSocPlanAddDTO.getEmpId());
            empSocRelatedDO.setSchemeId(empSocPlanAddDTO.getSchemeId());
            // 增加增员记录
            EmpSocPlanDO empSocPlanDO = empSocPlanAddDTO.to(EmpSocPlanDO.class);
            // 走到这个方法里说明需要确认增员 反馈状态设置为空
            // 这里的  EmpSocState  不是特指社保状态
            empSocPlanDO.setEmpSocState(plan ? EmpSocStatus.WAIT_INCREMENT.getValue() : EmpSocStatus.INCREMENT.getValue());
            // 更新员工增员时间
            empSocRelatedService.setPlanIncreaseDateByType(empSocPlanAddDTO.getType(), empSocRelatedDO, increaseDate);
            // 这里有可能是一个 empSocRelatedDO 会出现三次 更新三次太麻烦了 这里 记录一下需要更新的数据 拿出去更新,也会缩短执行时间
            if (!updateList.contains(empSocRelatedDO)) {
                updateList.add(empSocRelatedDO);
            }
            empSocPlanDO = empSocPlanService.save(empSocPlanDO, tokenUser.getSiteId(), tokenUser.getUserId());
            // 保存员工参保方案子项
            List<EmpSocPlanItemAddDTO> empSocPlanItemAddDTOList = empSocPlanAddDTO.getEmpSocPlanItemAddDTOList();
            ParamException.notEmpty(empSocPlanItemAddDTOList, "员工参保子项不能为空");
            String planId = empSocPlanDO.getId();
            List<EmpSocPlanItemDO> empSocPlanItemList = empSocPlanItemAddDTOList.stream().map(
                    empSocPlanItemAddDTO -> {
                        EmpSocPlanItemDO empSocPlanItemDO = empSocPlanItemAddDTO.to(EmpSocPlanItemDO.class);
                        empSocPlanItemDO.setId(null);
                        empSocPlanItemDO.setPlanId(planId);
                        empSocPlanItemDO.preInsert(tokenUser.getUserId());
                        empSocPlanItemDO.setSiteId(tokenUser.getSiteId());
                        return empSocPlanItemDO;
                    }
            ).collect(Collectors.toList());
            empSocPlanItemService.bachSave(empSocPlanItemList);
        }
        // 最后把员工更新一下
        for (EmpSocRelatedDO empSocRelatedDO : updateList) {
            empSocRelatedService.updateByIdSelective(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        if (saveCount > 1) {
            HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行社保增员 增员" + empName
                    + "等" + saveCount + "名员工", "EmpSocInfo", companyId, companyId, tokenUser);
        } else {
            HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行社保增员 增员员工" + empName,
                    "EmpSocInfo", companyId, companyId, tokenUser);
        }
        try {
            sendNoticeService.sendIncreaseDecreaseNotice(empId, companyId, saveCount, true);
        } catch (Exception e) {
            log.error("增员发送通知失败");
        }
        return batchIncreaseDTO.getYear() + "年" + batchIncreaseDTO.getMonth() + "月";
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void increaseUpdateExtra(IncreaseDecreaseUpdateDTO increaseUpdate, TokenUser tokenUser) {
        // 获取到修改后的增员计划
        EmpSocPlanUpdateDTO updateDTO = increaseUpdate.getEmpSocPlanUpdateDTO();
        EmpSocPlanDO empSocPlanDO = empSocPlanService.selectDOById(updateDTO.getId(), tokenUser.getSiteId());
        checkIncreaseUpdate(empSocPlanDO.getEmpId(), empSocPlanDO, tokenUser);
        EmpSocPlanDO socPlan = empSocPlanService.selectDOById(updateDTO.getId(), tokenUser.getSiteId());
        Integer feed = 1;
        if (feed.equals(socPlan.getFeedbackFlag())) {
            throw new ParamException("当前计划已被反馈");
        }
        if (ObjectUtils.isEmpty(updateDTO.getFeedbackFlag())) {
            empSocPlanDO.setFeedbackFlag(null);
            empSocPlanService.updateById(empSocPlanDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        // 获取员工花名册信息,log日至需要
        EmpInfoDO empInfoDO = empInfoService.selectDOById(updateDTO.getEmpId(), tokenUser.getSiteId());
        Date planIncreaseDate = DateKit8.parse(updateDTO.getYear() + "-" + updateDTO.getMonth() + "-01", "yyyy-MM-dd");
        // 判断一下是不是待增
        boolean plan = !CollectionUtils.isEmpty(DateUtils.getMonthDifferences(new Date(), planIncreaseDate));
        if (plan) {
            updateDTO.setEmpSocState(WAIT_INCREMENT.getValue());
        } else {
            updateDTO.setEmpSocState(INCREMENT.getValue());
        }
        EmpSocRelatedDO empSocRelatedDO = empSocRelatedService
                .selectByEmpId(updateDTO.getEmpId(), tokenUser.getSiteId());
        // 更新员工社保相关信息
        empSocRelatedService.updatePlanDateByIncreaseMsg(updateDTO.getType(), empSocRelatedDO, planIncreaseDate,
                updateDTO.getSchemeId(), tokenUser);
        List<EmpSocPlanItemUpdateDTO> itemUpdateList = updateDTO.getItemUpdateList();
        // 删除原来里面的子项
        empSocPlanItemService.deleteByPlanId(updateDTO.getId(), tokenUser);
        // 更新金额,并且重新添加子项
        updateAmountByItemList(itemUpdateList, updateDTO, tokenUser);
        // log日志
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行增员编辑 编辑员工" + empInfoDO.getName(),
                "EmpInfo", updateDTO.getId(), empInfoDO.getCompanyId(), tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void increaseFeedbackExtra(EmpSocPlanAttachDTO empSocPlanAttachDTO, TokenUser tokenUser) {
        List<EmpSocPlanDO> empSocPlanList = empSocPlanService
                .selectByIdList(empSocPlanAttachDTO.getSocPlanIdList(), tokenUser.getSiteId());
        String companyId = empSocPlanList.get(0).getCompanyId();
        // 取出所有员工Id
        List<String> empIdList = empSocPlanList.stream()
                .map(EmpSocPlanDO::getEmpId).distinct().collect(Collectors.toList());
        // 取出所有计划Id
        List<String> planIdList = empSocPlanList.stream()
                .map(EmpSocPlanDO::getId).collect(Collectors.toList());
        // 取出所有年月拼接起来并且过滤
        List<String> dateStrList = empSocPlanList.stream()
                .map(empSocPlan -> empSocPlan.getYear() + empSocPlan.getMonth())
                .distinct().collect(Collectors.toList());
        List<String> schemeIdList = empSocPlanList.stream().map(EmpSocPlanDO::getSchemeId).collect(Collectors.toList());
        List<SocProgDO> socSchemeList = socSchemeService.selectByIdList(schemeIdList, tokenUser);
        Map<String, SocProgDO> schemeMap = socSchemeList.stream().collect(Collectors.toMap(SocProgDO::getId, v -> v));
        // 根据这些字符串查询对应的参保月
        List<EmpSocMonthListVO> empSocMonthList = empSocMonthService
                .selectByMonthByDateStrList(companyId, dateStrList, tokenUser.getSiteId());
        Map<String, EmpSocMonthListVO> dateStrMap = empSocMonthList.stream()
                .collect(Collectors.toMap(EmpSocMonthListVO::getDateStr, v -> v));
        // 查询员工Id列表员工
        List<EmpInfoDO> empInfoList = empInfoService.selectDoByIds(empIdList);
        Map<String, EmpSocRelatedDO> empSocRelatedMap = empSocRelatedService
                .selectByEmpIdList(empIdList, tokenUser.getSiteId())
                .stream().collect(Collectors.toMap(EmpSocRelatedDO::getEmpId, v -> v));
        Map<String, EmpInfoDO> empInfoMap = empInfoList
                .stream().collect(Collectors.toMap(EmpInfoDO::getId, v -> v));
        Map<String, List<EmpSocPlanItemDO>> planItemMap = empSocPlanItemService.selectByPlanIdList(planIdList, tokenUser);
        List<SocPlanFeedbackRecordDO> feedBackList = new ArrayList<>();
        this.saveFeedbackRecord(empSocPlanAttachDTO, tokenUser);
        for (EmpSocPlanDO empSocPlanDO : empSocPlanList) {
            String feedbackState = 2 == empSocPlanAttachDTO.getExecuteResult() ? "失败" : "成功";
            feedBackList.add(socPlanFeedbackRecordService.initRecord(feedbackState, empSocPlanDO.getId(),
                    empSocPlanAttachDTO, tokenUser));
            empSocPlanDO.setFeedbackFlag(empSocPlanAttachDTO.getExecuteResult());
            EmpSocRelatedDO empSocRelatedDO = empSocRelatedMap.get(empSocPlanDO.getEmpId());
            // 如果执行失败
            if (2 == empSocPlanAttachDTO.getExecuteResult()) {
                if (!StringUtils.isEmpty(empSocPlanAttachDTO.getFailCause())) {
                    empSocPlanDO.setFailCause(empSocPlanAttachDTO.getFailCause());
                }
                empSocRelatedService.clearedPlanIncreaseDate(empSocRelatedDO, empSocPlanDO.getType(), tokenUser);
            } else {
                List<EmpSocPlanItemDO> planItemList = planItemMap.get(empSocPlanDO.getId());
                EmpInfoDO empInfo = empInfoMap.get(empSocPlanDO.getEmpId());
                empSocRelatedService.checkIncreaseDate(empSocRelatedDO, empSocPlanDO, empInfo);
                SocProgDO socScheme = schemeMap.get(empSocPlanDO.getSchemeId());
                empSocRelatedService.setAccountByScheme(empSocPlanDO.getType(), empSocRelatedDO, socScheme);
                // 更新员工社保信息
                empSocRelatedService.updateIncreaseDate(empSocRelatedDO, empSocPlanDO.getType(), false, tokenUser);
                EmpSocMonthListVO empSocMonthListVO = dateStrMap.get(empSocPlanDO.getYear() + empSocPlanDO.getMonth());
                if (ObjectUtils.isEmpty(empSocMonthListVO)) {
                    empSocPlanService.updateByIdSelective(empSocPlanDO, tokenUser.getSiteId(), tokenUser.getUserId());
                    continue;
                }
                String monthId = empSocMonthListVO.getId();
                if (!StringUtils.isEmpty(monthId)) {
                    // 校验这个月 有没有账单  账单是否在审批
                    empSocTransformService.checkCostBillByMonthId(monthId, empSocPlanDO.getMonth(), tokenUser);
                }
                EmpSocMonthDO month = empSocMonthListVO.to(EmpSocMonthDO.class);
                empSocPlanService.increaseMerge(planItemList, month, empInfo, empSocPlanDO, tokenUser, false);
                List<EmpSocMonthDO> futureMonthList = empSocMonthDAO.selectMonthIdListAfterDate(empSocPlanDO.getYear() +
                        empSocPlanDO.getMonth(), companyId, tokenUser.getSiteId());
                if (!CollectionUtils.isEmpty(futureMonthList)) {
                    for (EmpSocMonthDO futureMonth : futureMonthList) {
                        empSocPlanService.increaseMerge(planItemList, futureMonth, empInfo, empSocPlanDO, tokenUser, true);
                    }
                    // 更新员工社保信息
                    empSocRelatedService.updateNormalStatus(empSocRelatedDO, empSocPlanDO.getType(), tokenUser);
                }
                //用工档案
                String desc = "由管理员" + tokenUser.getUserName() +
                        ",办理" + conversionType(empSocPlanDO.getType()) + PersonalEventEnum.INCREASE.getDesc() +
                        ",参保时间: " + empSocPlanDO.getYear() + "-" + empSocPlanDO.getMonth();
                personalEventService.autoSave(empInfo.to(EmpInfoVO.class), tokenUser, desc,
                        PersonalEventEnum.INCREASE.getValue(), PersonalEventEnum.INCREASE.getDesc());
            }
            if (empSocPlanList.size() == 1) {
                EmpSocPlanDO async = empSocPlanService.selectDOById(empSocPlanDO.getId(), tokenUser.getSiteId());
                if (!ObjectUtils.isEmpty(async.getFeedbackFlag())) {
                    throw new ParamException("当前计划已被反馈");
                }
            }
            empSocPlanService.updateByIdSelective(empSocPlanDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        if (!CollectionUtils.isEmpty(feedBackList)) {
            socPlanFeedbackRecordService.bachSave(feedBackList);
        }
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行增员标记", "EmpSocInfo",
                companyId, companyId, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<CheckDecreaseFailVO> decreaseExtra(IncreaseDecreaseQuery increaseDecreaseQuery, TokenUser tokenUser) {

        List<CheckDecreaseFailVO> checkDecreaseFailList = new ArrayList<>();
        List<String> decreaseEmpIdList = increaseDecreaseQuery.getEmpIdList();
        ParamException.notEmpty(decreaseEmpIdList, "未选择减员人员");
        List<EmpInfoDO> empInfoList = empInfoService.selectDoByIds(decreaseEmpIdList);
        ParamException.notEmpty(empInfoList, "选择的员工不存在或已被删除");
        Map<String, EmpInfoDO> empInfoMap = empInfoList.stream()
                .collect(Collectors.toMap(EmpInfoDO::getId, v -> v));
        // 记录减员人数和第一个人员的名字和Id最后记录日志和发通知用
        int decreaseCount = decreaseEmpIdList.size();
        String tempEmpName = empInfoList.get(0).getName();
        String tempEmpId = empInfoList.get(0).getId();
        // 校验传进来的这些人可不可以减员,不可以的返回前端,不报错
        List<CheckDecreaseVO> checkDecreaseList = empSocPlanService.checkDecrease(decreaseEmpIdList, tokenUser);
        Map<String, CheckDecreaseVO> checkDecreaseMap = checkDecreaseList.stream()
                .collect(Collectors.toMap(CheckDecreaseVO::getEmpId, v -> v));
        List<EmpSocRelatedDO> empSocRelatedList = empSocRelatedService
                .selectByEmpIdList(decreaseEmpIdList, tokenUser.getSiteId());
        String companyId = increaseDecreaseQuery.getCompanyId();
        List<EmpSocPlanDO> insertList = new ArrayList<>();
        // 未完结的待遇处理事件也会报错
        List<TreatmentDisposeEventDO> eventList = treatmentDisposeEventService
                .findNotFinishedEventByEmpIdList(decreaseEmpIdList, tokenUser);
        List<String> eventEmpIdList = eventList.stream()
                .map(TreatmentDisposeEventDO::getEmpId).distinct().collect(Collectors.toList());
        for (EmpSocRelatedDO empSocRelatedDO : empSocRelatedList) {
            EmpInfoDO empInfoDO = empInfoMap.get(empSocRelatedDO.getEmpId());
            CheckDecreaseVO checkDecreaseVO = checkDecreaseMap.get(empSocRelatedDO.getEmpId());
            CheckDecreaseFailVO checkDecreaseFailVO = new CheckDecreaseFailVO();
            checkDecreaseFailVO.setEmpId(empInfoDO.getId());
            checkDecreaseFailVO.setEmpName(empInfoDO.getName());
            if (increaseDecreaseQuery.getStopSoc()) {
                if (checkDecreaseVO.getSocNoPayment()) {
                    checkDecreaseFailVO.setSocDescription("无参保记录或已减员");
                } else if (eventEmpIdList.contains(empSocRelatedDO.getEmpId())) {
                    checkDecreaseFailVO.setSocDescription("待遇处理存在未完结事件");
                } else {
                    checkDecreaseFailVO.setSocDescription("计划创建成功");
                    String stopSocYear = increaseDecreaseQuery.getPlanStopSocYear();
                    String stopSocMonth = increaseDecreaseQuery.getPlanStopSocMonth();
                    // 创建一条减员记录
                    insertList.add(empSocPlanService.initDecreasePlanByType2(companyId, SOC_ITEM_TYPE, stopSocYear, stopSocMonth,
                            empSocRelatedDO.getEmpId(), increaseDecreaseQuery.getServiceCost(), tokenUser));
                    Date stopSocDate = DateKit8.parseDate(stopSocYear + "-" + stopSocMonth + "-01");
                    // 更新员工的减员时间和状态
                    empSocRelatedService.setStopDateByType2(empSocRelatedDO, SOC_ITEM_TYPE, stopSocDate);
                }
            }
            if (increaseDecreaseQuery.getStopMe()) {
                if (checkDecreaseVO.getMeNoPayment()) {
                    checkDecreaseFailVO.setMeDescription("无参保记录或已减员");
                } else if (eventEmpIdList.contains(empSocRelatedDO.getEmpId())) {
                    checkDecreaseFailVO.setSocDescription("待遇处理存在未完结事件");
                } else {
                    checkDecreaseFailVO.setMeDescription("计划创建成功");
                    String stopMeYear = increaseDecreaseQuery.getPlanStopMeYear();
                    String stopMeMonth = increaseDecreaseQuery.getPlanStopMeMonth();
                    // 创建一条减员记录
                    insertList.add(empSocPlanService.initDecreasePlanByType2(companyId, ME_ITEM_TYPE, stopMeYear, stopMeMonth,
                            empSocRelatedDO.getEmpId(), increaseDecreaseQuery.getServiceCost(), tokenUser));
                    Date planStopMeDate = DateKit8.parseDate(stopMeYear + "-" + stopMeMonth + "-01");
                    // 更新员工的减员时间和状态
                    empSocRelatedService.setStopDateByType2(empSocRelatedDO, ME_ITEM_TYPE, planStopMeDate);
                }
            }
            if (increaseDecreaseQuery.getStopPf()) {
                if (checkDecreaseVO.getPfNoPayment()) {
                    checkDecreaseFailVO.setPfDescription("无参保记录或已减员");
                } else if (eventEmpIdList.contains(empSocRelatedDO.getEmpId())) {
                    checkDecreaseFailVO.setSocDescription("待遇处理存在未完结事件");
                } else {
                    checkDecreaseFailVO.setPfDescription("计划创建成功");
                    String sealedDateYear = increaseDecreaseQuery.getSealedDateYear();
                    String sealedDateMonth = increaseDecreaseQuery.getSealedDateMonth();
                    // 创建一条减员记录
                    insertList.add(empSocPlanService.initDecreasePlanByType2(companyId, PF_ITEM_TYPE, sealedDateYear, sealedDateMonth,
                            empSocRelatedDO.getEmpId(), increaseDecreaseQuery.getServiceCost(), tokenUser));
                    Date sealedDateDate = DateKit8.parseDate(sealedDateYear + "-" + sealedDateMonth + "-01");
                    // 更新员工的计划时间和状态
                    empSocRelatedService.setStopDateByType2(empSocRelatedDO, PF_ITEM_TYPE, sealedDateDate);
                }
            }
            checkDecreaseFailList.add(checkDecreaseFailVO);
            empSocRelatedService.updateByIdSelective(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        empSocPlanDAO.insertListAndSetId(insertList);
        if (decreaseCount > 1) {
            HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行减员 减员" + tempEmpName
                    + "等" + decreaseCount + "名员工", "EmpSocInfo", companyId, companyId, tokenUser);
        } else {
            HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行减员 减员员工" + tempEmpName,
                    "EmpSocInfo", companyId, companyId, tokenUser);
        }
        try {
            sendNoticeService.sendIncreaseDecreaseNotice(tempEmpId, companyId, decreaseCount, true);
        } catch (Exception e) {
            log.error("减员发送通知失败");
        }
        return checkDecreaseFailList;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void decreaseUpdateExtra(IncreaseDecreaseUpdateDTO increaseDecreaseUpdate, TokenUser tokenUser) {
        String year = increaseDecreaseUpdate.getYear();
        String month = increaseDecreaseUpdate.getMonth();
        String planId = increaseDecreaseUpdate.getPlanId();
        Date planDecrease = DateKit8.parse(year + "-" + month + "-01", "yyyy-MM-dd");
        EmpSocPlanDO empSocPlanDO = empSocPlanService.selectDOById(planId, tokenUser.getSiteId());
        checkDecreaseUpdate(empSocPlanDO.getEmpId(), empSocPlanDO, tokenUser);
        // 查询花名册信息,下面log日志用
        EmpInfoDO empInfoDO = empInfoService.selectDOById(empSocPlanDO.getEmpId(), tokenUser.getSiteId());
        // 判断一下是不是待减
        boolean plan = !CollectionUtils.isEmpty(DateUtils.getMonthDifferences(new Date(), planDecrease));
        if (plan) {
            empSocPlanDO.setEmpSocState(WAIT_ATTRITION.getValue());
        } else {
            empSocPlanDO.setEmpSocState(ATTRITION.getValue());
        }
        EmpSocPlanDO socPlan = empSocPlanService.selectDOById(increaseDecreaseUpdate.getPlanId(), tokenUser.getSiteId());
        Integer feed = 1;
        if (feed.equals(socPlan.getFeedbackFlag())) {
            throw new ParamException("当前计划已被反馈");
        }
        empSocPlanDO.setYear(year);
        empSocPlanDO.setMonth(month);
        empSocPlanDO.setFeedbackFlag(null);
        EmpSocRelatedDO empSocRelatedDO = empSocRelatedService
                .selectByEmpId(empSocPlanDO.getEmpId(), tokenUser.getSiteId());
        empSocRelatedService.updatePlanDateByDecreaseMsg(empSocRelatedDO, empSocPlanDO.getType(), planDecrease);
        if (!StringUtils.isEmpty(increaseDecreaseUpdate.getServiceCost())) {
            empSocPlanDO.setServiceCost(new BigDecimal(increaseDecreaseUpdate.getServiceCost()));
        } else {
            empSocPlanDO.setServiceCost(null);
        }
        empSocPlanService.updateById(empSocPlanDO, tokenUser.getSiteId(), tokenUser.getUserId());
        empSocRelatedService.updateByIdSelective(empSocRelatedDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // log日志
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "减员编辑 编辑员工" + empInfoDO.getName(),
                "EmpInfo", empSocPlanDO.getId(), empSocPlanDO.getCompanyId(), tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void decreaseFeedbackExtra(EmpSocPlanAttachDTO empSocPlanAttachDTO, TokenUser tokenUser) {
        List<EmpSocPlanDO> empSocPlanList = empSocPlanService
                .selectByIdList(empSocPlanAttachDTO.getSocPlanIdList(), tokenUser.getSiteId());
        String companyId = empSocPlanList.get(0).getCompanyId();
        List<String> empIdList = empSocPlanList.stream()
                .map(EmpSocPlanDO::getEmpId).distinct().collect(Collectors.toList());
        // 员工花名册信息查询
        List<EmpInfoDO> empInfoList = empInfoService.selectDoByIds(empIdList);
        Map<String, EmpInfoDO> empInfoMap = empInfoList.stream().collect(Collectors.toMap(EmpInfoDO::getId, v -> v));
        // 员工社保相关信息查询
        Map<String, EmpSocRelatedDO> empSocRelatedMap = empSocRelatedService
                .selectByEmpIdList(empIdList, tokenUser.getSiteId())
                .stream().collect(Collectors.toMap(EmpSocRelatedDO::getEmpId, v -> v));
        List<SocPlanFeedbackRecordDO> feedBackList = new ArrayList<>();
        this.saveFeedbackRecord(empSocPlanAttachDTO, tokenUser);
        for (EmpSocPlanDO empSocPlan : empSocPlanList) {
            String feedbackState = 2 == empSocPlanAttachDTO.getExecuteResult() ? "失败" : "成功";
            feedBackList.add(socPlanFeedbackRecordService.initRecord(feedbackState, empSocPlan.getId(),
                    empSocPlanAttachDTO, tokenUser));
            EmpSocRelatedDO empSocRelated = empSocRelatedMap.get(empSocPlan.getEmpId());
            // 如果执行失败
            empSocPlan.setFeedbackFlag(empSocPlanAttachDTO.getExecuteResult());
            if (2 == empSocPlanAttachDTO.getExecuteResult()) {
                String failCause = empSocPlanAttachDTO.getFailCause();
                if (!StringUtils.isEmpty(failCause)) {
                    if (failCause.length() > 200) {
                        throw new ParamException("失败原因不可超过200字");
                    }
                    empSocPlan.setFailCause(failCause);
                }
                empSocRelatedService.clearedPlanDecreaseDate(empSocRelated, empSocPlan.getType(), tokenUser);
            } else {
                EmpInfoDO empInfoDO = empInfoMap.get(empSocPlan.getEmpId());
                empSocRelatedService.checkDecreaseDate(empSocRelated, empSocPlan, empInfoDO);
                // 更新员工社保信息
                empSocRelatedService.updateDecreaseDate(empSocRelated, empSocPlan.getType(), false, tokenUser);
                String monthId = empSocMonthService.selectMonthIdByYearAndMonth(companyId,
                        empSocPlan.getYear(), empSocPlan.getMonth(), tokenUser.getSiteId());
                empSocPlanService.decreaseMerge(monthId, empSocPlan, false, tokenUser);
                if (!StringUtils.isEmpty(monthId)) {
                    // 校验这个月 有没有账单  账单是否在审批
                    empSocTransformService.checkCostBillByMonthId(monthId, empSocPlan.getMonth(), tokenUser);
                    List<EmpSocMonthDO> monthList = empSocMonthDAO.selectMonthIdListAfterDate(empSocPlan.getYear() +
                            empSocPlan.getMonth(), companyId, tokenUser.getSiteId());
                    if (!CollectionUtils.isEmpty(monthList)) {
                        for (EmpSocMonthDO month : monthList) {
                            empSocPlanService.decreaseMerge(month.getId(), empSocPlan, true, tokenUser);
                        }
                        // 更新员工社保信息
                        empSocRelatedService.updateStopStatus(empSocRelated, empSocPlan.getType(), tokenUser);
                    }
                }
                //用工档案
                String desc = "由管理员" + tokenUser.getUserName() +
                        ",办理" + conversionType(empSocPlan.getType()) + PersonalEventEnum.DECREASE.getDesc() +
                        ",减员时间: " + empSocPlan.getYear() + "-" + empSocPlan.getMonth();
                personalEventService.autoSave(empInfoDO.to(EmpInfoVO.class), tokenUser, desc,
                        PersonalEventEnum.DECREASE.getValue(), PersonalEventEnum.DECREASE.getDesc());
            }
            if (empSocPlanList.size() == 1) {
                EmpSocPlanDO async = empSocPlanService.selectDOById(empSocPlan.getId(), tokenUser.getSiteId());
                if (!ObjectUtils.isEmpty(async.getFeedbackFlag())) {
                    throw new ParamException("当前计划已被反馈");
                }
            }
            empSocPlanService.updateByIdSelective(empSocPlan, tokenUser.getSiteId(), tokenUser.getUserId());
        }
        if (!CollectionUtils.isEmpty(feedBackList)) {
            socPlanFeedbackRecordService.bachSave(feedBackList);
        }
        HrLogKit.logForSave("由管理员" + tokenUser.getUserName() + "进行减员标记", "EmpSocInfo",
                companyId, companyId, tokenUser);
    }

    @Override
    public JfEmpSocInfoVO jfEmpSocInfo(String empId, TokenUser tokenUser) {
        JfEmpSocInfoVO result = new JfEmpSocInfoVO();
        EmpSocRelatedDO empSocRelated = empSocRelatedService.selectByEmpId(empId, tokenUser.getSiteId());
        // 查询参保方案
        if (!StringUtils.isEmpty(empSocRelated.getSchemeId())) {
            SocProgDO socScheme = socSchemeService.selectDOById(empSocRelated.getSchemeId(), tokenUser.getSiteId());
            result.setProgName(socScheme.getProgName());
            List<SocProgItemDO> schemeItemList = socSchemeItemService
                    .selectBySocProgId(empSocRelated.getSchemeId(), tokenUser.getSiteId());
            if (!CollectionUtils.isEmpty(schemeItemList)) {
                result.setSchemeItemList(schemeItemList);
            }
        }
        // 查询此人的参保记录
        List<EmpSocInfoDO> empSocInfoList = empSocInfoService.selectByEmpId(empId, tokenUser);
        if (!CollectionUtils.isEmpty(empSocInfoList)) {
            List<String> infoIdList = empSocInfoList.stream().map(EmpSocInfoDO::getId).collect(Collectors.toList());
            // 需要添加差额费用
            List<SocDifferenceDO> socDifferenceList = socDifferenceService
                    .selectBySocInfoIdList(infoIdList, tokenUser.getSiteId());
            Map<String, List<SocDifferenceDO>> groupInfo = socDifferenceList.stream()
                    .collect(Collectors.groupingBy(SocDifferenceDO::getSocInfoId));
            List<EmpSocInfoListVO> resultSocInfoList = empSocInfoList.stream().map(socInfo -> {
                EmpSocInfoListVO toResult = socInfo.to(EmpSocInfoListVO.class);
                SocProgDO infoScheme = socSchemeService.selectDOById(socInfo.getProgId(), tokenUser.getSiteId());
                if (!ObjectUtils.isEmpty(infoScheme)) {
                    toResult.setSocCityName(infoScheme.getSocCityName());
                    toResult.setProgName(infoScheme.getProgName());
                } else {
                    toResult.setSocCityName("");
                    toResult.setProgName("");
                }
                toResult.setSocAmount(toResult.getCompanySocAmount().add(toResult.getPersonalSocAmount()));
                toResult.setPfAmount(toResult.getCompanyPfAmount().add(toResult.getPersonalPfAmount()));
                toResult.setSocDateStr(toResult.getYear() + "-" + toResult.getMonth());
                toResult.setPayCostTypeStr(SocPayCostType.find(toResult.getPayCostType()).getDesc());
                // 填充差额费用
                toResult.setData(fillDifference(groupInfo, socInfo.getId()));
                return toResult;
            }).sorted(Comparator.comparing(EmpSocInfoListVO::getSocDateStr).reversed()).collect(Collectors.toList());
            result.setSocInfoList(resultSocInfoList);
        }
        return result;
    }

    @Override
    public Page<EmpSocInfoListVO> jfEmpSocInfoList(EmpSocInfoQuery empSocInfoQuery, TokenUser tokenUser) {
        if (!StringUtils.isEmpty(empSocInfoQuery.getDate())) {
            String[] yearAnfMonth = empSocInfoQuery.getDate().split("-");
            String monthId = empSocMonthService.selectMonthIdByYearAndMonth
                    (empSocInfoQuery.getCompanyId(), yearAnfMonth[0], yearAnfMonth[1], tokenUser.getSiteId());
            if (StringUtils.isEmpty(monthId)) {
                return new Page<>(empSocInfoQuery.getPageSize(), empSocInfoQuery.getPageNo());
            }
            empSocInfoQuery.setMonthId(monthId);
        }
        List<EmpSocInfoListVO> infoList = empSocInfoService.jfEmpSocInfoList(empSocInfoQuery, tokenUser.getSiteId());
        if (CollectionUtils.isEmpty(infoList)) {
            return new Page<>(empSocInfoQuery.getPageSize(), empSocInfoQuery.getPageNo());
        }
        Page<EmpSocInfoListVO> resultPage = PageKit
                .startPage(infoList, empSocInfoQuery.getPageNo(), empSocInfoQuery.getPageSize());
        List<EmpSocInfoListVO> entities = resultPage.getEntities();
        if (!CollectionUtils.isEmpty(entities)) {
            List<String> infoIdList = entities.stream().map(EmpSocInfoListVO::getId).collect(Collectors.toList());
            List<String> schemeIdList = entities.stream().map(EmpSocInfoListVO::getProgId).collect(Collectors.toList());
            List<EmpSocItemDO> empSocItemList = empSocItemService.selectByEmpSocIdList(infoIdList, tokenUser.getSiteId());
            List<SocProgItemDO> socSchemeItemList = socSchemeItemService.selectBySocProgIds(schemeIdList, tokenUser);
            List<SocDifferenceDO> socDifferenceList = socDifferenceService
                    .selectBySocInfoIdList(infoIdList, tokenUser.getSiteId());
            Map<String, List<SocDifferenceDO>> groupInfo = socDifferenceList.stream()
                    .collect(Collectors.groupingBy(SocDifferenceDO::getSocInfoId));
            Map<String, List<EmpSocItemDO>> groupSocItem = empSocItemList.stream()
                    .collect(Collectors.groupingBy(EmpSocItemDO::getEmpSocId));
            Map<String, List<SocProgItemDO>> groupSchemeItem = socSchemeItemList.stream()
                    .collect(Collectors.groupingBy(SocProgItemDO::getProgId));
            for (EmpSocInfoListVO entity : entities) {
                List<SocProgItemDO> schemeItemList = groupSchemeItem.get(entity.getProgId());
                Map<Integer, String> statusMap = new LinkedHashMap<>(8);
                entity.setEmpSocStatusStr(EmpSocStatus.find(entity.getEmpSocStatus()).getDesc());
                statusMap.put(1, entity.getEmpSocStatusStr());
                entity.setEmpMeStatusStr(EmpSocStatus.find(entity.getEmpMeStatus()).getDesc());
                statusMap.put(3, entity.getEmpMeStatusStr());
                entity.setEmpPfStatusStr(EmpSocStatus.find(entity.getEmpPfStatus()).getDesc());
                statusMap.put(2, entity.getEmpPfStatusStr());
                Integer gender = entity.getGender();
                if (!ObjectUtils.isEmpty(gender)) {
                    entity.setSex(gender == 1 ? "男" : "女");
                }
                Boolean empIsValid = entity.getEmpIsValid();
                entity.setEmpIsValid(!ObjectUtils.isEmpty(empIsValid) && empIsValid);
                entity.setSocCityName(StringUtils.isEmpty(entity.getSocCityName()) ? "" : entity.getSocCityName());
                entity.setProgName(StringUtils.isEmpty(entity.getProgName()) ? "" : entity.getProgName());
                if (!SocPayCostType.NORMAL_PAY_COST.getValue().equals(entity.getPayCostType())) {
                    entity.setPayCostTypeStr(entity.getSocDateStr() + SocPayCostType.find(entity.getPayCostType()).getDesc());
                } else {
                    entity.setPayCostTypeStr(SocPayCostType.find(entity.getPayCostType()).getDesc());
                }
                Map<String, Object> data = fillDifference(groupInfo, entity.getId());
                Map<String, String> itemStatusMap = this.constructStatus(statusMap, schemeItemList);
                entity.setStatusMap(itemStatusMap);
                List<EmpSocItemDO> socItemList = groupSocItem.get(entity.getId());
                this.setItemAmountData(socItemList, data);
                entity.setData(data);
            }
        }
        return resultPage;
    }


    @Override
    public JfStatisticsAnalyseVO jfStatisticsAnalyseSoc(EmpSocInfoQuery empSocInfoQuery, TokenUser tokenUser) {
        String currentYear = empSocInfoQuery.getYear();
        String companyId = empSocInfoQuery.getCompanyId();
        JfStatisticsAnalyseVO result = new JfStatisticsAnalyseVO();
        List<String> monthList = DateUtils.getMonthList();
        result.setStatisticsName("社保成本");
        result.setYear(currentYear);
        List<JfStatisticsAnalyseItemVO> itemList = new ArrayList<>();
        for (String monthStr : monthList) {
            JfStatisticsAnalyseItemVO item = new JfStatisticsAnalyseItemVO();
            item.setMonth(monthStr);
            // 计算当年度
            String currentMonthId = empSocMonthService
                    .selectMonthIdByYearAndMonth(companyId, currentYear, monthStr, tokenUser.getSiteId());
            BigDecimal amountCurrent = new BigDecimal("0");
            if (StringUtils.isEmpty(currentMonthId)) {
                item.setYearCurrent(amountCurrent);
            } else {
                amountCurrent = jfCalculateAmount(currentMonthId, companyId, tokenUser);
                item.setYearCurrent(amountCurrent);
            }
            // 计算上年度
            String formerYear = (Integer.parseInt(currentYear) - 1) + "";
            String formerMonthId = empSocMonthService
                    .selectMonthIdByYearAndMonth(companyId, formerYear, monthStr, tokenUser.getSiteId());
            BigDecimal amountFormer = new BigDecimal("0");
            if (StringUtils.isEmpty(formerMonthId)) {
                item.setYearFormer(amountFormer);
            } else {
                amountFormer = jfCalculateAmount(formerMonthId, companyId, tokenUser);
                item.setYearFormer(amountFormer);
            }
            BigDecimal yearOverYearGrowthRate = null;
            if (amountCurrent.compareTo(BigDecimal.ZERO) != 0 && amountFormer.compareTo(BigDecimal.ZERO) != 0) {
                yearOverYearGrowthRate = amountCurrent.subtract(amountFormer)
                        .divide(amountFormer, 4, RoundingMode.HALF_UP);
            }
            item.setYearOverYearGrowthRate(yearOverYearGrowthRate);
            itemList.add(item);
        }
        result.setItemList(itemList);
        return result;
    }

    public void saveFeedbackRecord(EmpSocPlanAttachDTO empSocPlanAttachDTO, TokenUser tokenUser) {
        String annexVerifyBySite = getAnnexVerifyBySite(tokenUser);
        String remarkVerifyBySite = getRemarkVerifyBySite(tokenUser);
        if (2 == empSocPlanAttachDTO.getExecuteResult()) {
            // 失败时校验备注必填
            if (NEED_CONFIRM.equals(remarkVerifyBySite) && StringUtils.isEmpty(empSocPlanAttachDTO.getFeedbackContent())) {
                throw new ParamException("执行失败时,备注必填");
            }
        } else {
            // 成功时校验附件必填
            if (NEED_CONFIRM.equals(annexVerifyBySite) && StringUtils.isEmpty(empSocPlanAttachDTO.getAnnex())) {
                throw new ParamException("执行成功时,附件必填");
            }
        }
    }

    /**
     * 甲方端社保统计分析计算金额
     */
    private BigDecimal jfCalculateAmount(String monthId, String companyId, TokenUser tokenUser) {
        List<EmpSocInfoDO> empSocInfoList = empSocInfoService
                .selectByCompanyAndMonthId(companyId, monthId, tokenUser.getSiteId());
        List<SocDifferenceDO> socDifferenceList = socDifferenceService.selectByMonthId(monthId, tokenUser);
        BigDecimal amount = new BigDecimal(0);
        for (EmpSocInfoDO empSocInfo : empSocInfoList) {
            amount = amount.add(empSocInfo.getCompanySocAmount())
                    .add(empSocInfo.getCompanyPfAmount());
        }
        for (SocDifferenceDO socDifference : socDifferenceList) {
            amount = amount.add(socDifference.getCompanyDifference());
        }
        return amount;
    }

    /**
     * 甲方端小程序,把三种状态赋值给对应的子项
     */
    private Map<String, String> constructStatus(Map<Integer, String> socStatusMap, List<SocProgItemDO> schemeItemList) {
        Map<String, String> statusMap = new LinkedHashMap<>(8);
        for (SocProgItemDO schemeItem : schemeItemList) {
            statusMap.put(schemeItem.getItemName(), socStatusMap.get(schemeItem.getItemType()));
        }
        return statusMap;
    }

    /**
     * 甲方端小程序,子项金额
     */
    private void setItemAmountData(List<EmpSocItemDO> socItemList, Map<String, Object> data) {
        if (CollectionUtils.isEmpty(socItemList)) {
            return;
        }
        for (EmpSocItemDO item : socItemList) {
            data.put(item.getItemName() + "(个人缴费)", item.getAmountPersonal());
            data.put(item.getItemName() + "(单位缴费)", item.getAmountCompany());
        }
    }

    /**
     * 填充差额费用
     */
    private Map<String, Object> fillDifference(Map<String, List<SocDifferenceDO>> groupInfo, String infoId) {
        List<SocDifferenceDO> differenceList = groupInfo.get(infoId);
        Map<String, Object> data = new LinkedHashMap<>(8);
        if (!CollectionUtils.isEmpty(differenceList)) {
            for (SocDifferenceDO socDifference : differenceList) {
                if (!ObjectUtils.isEmpty(socDifference.getPersonalDifference()) &&
                        socDifference.getPersonalDifference().compareTo(BigDecimal.ZERO) != 0) {
                    data.put(socDifference.getDifferenceName() + "(个人)", socDifference.getPersonalDifference());
                }
                if (!ObjectUtils.isEmpty(socDifference.getCompanyDifference()) &&
                        socDifference.getCompanyDifference().compareTo(BigDecimal.ZERO) != 0) {
                    data.put(socDifference.getDifferenceName() + "(单位)", socDifference.getCompanyDifference());
                }
            }
        }
        return data;
    }

    /**
     * 校验重复增员
     */
    private void checkRepeatIncrease(Map<String, EmpSocRelatedDO> empSocRelatedMap, Map<String, EmpInfoDO> empInfoMap,
                                     List<EmpSocPlanAddDTO> addPlanList) {
        for (EmpSocPlanAddDTO empSocPlanAddDTO : addPlanList) {
            EmpInfoDO empInfo = empInfoMap.get(empSocPlanAddDTO.getEmpId());
            EmpSocRelatedDO empSocRelated = empSocRelatedMap.get(empSocPlanAddDTO.getEmpId());
            Integer type = empSocPlanAddDTO.getType();
            checkRepeatIncreaseSingle(empSocRelated, empInfo, type);
        }
    }

    private void checkRepeatIncreaseSingle(EmpSocRelatedDO empSocRelated, EmpInfoDO empInfo, Integer type) {
        List<Integer> checkStateList = Arrays.asList(INCREMENT.getValue(),
                WAIT_INCREMENT.getValue(), NORMAL_SOC.getValue());
        if (SOC_ITEM_TYPE.equals(type)) {
            Date socPlanIncreaseDate = empSocRelated.getSocPlanIncreaseDate();
            Integer socState = empSocRelated.getSocState();
            if (!ObjectUtils.isEmpty(socPlanIncreaseDate) || checkStateList.contains(socState)) {
                throw new ParamException("员工" + empInfo.getName() + SOC_STR + "重复增员");
            }
        } else if (ME_ITEM_TYPE.equals(type)) {
            Date mePlanIncreaseDate = empSocRelated.getMePlanIncreaseDate();
            Integer meState = empSocRelated.getMeState();
            if (!ObjectUtils.isEmpty(mePlanIncreaseDate) || checkStateList.contains(meState)) {
                throw new ParamException("员工" + empInfo.getName() + ME_STR + "重复增员");
            }
        } else {
            Date pfPlanIncreaseDate = empSocRelated.getPfPlanIncreaseDate();
            Integer pfState = empSocRelated.getPfState();
            if (!ObjectUtils.isEmpty(pfPlanIncreaseDate) || checkStateList.contains(pfState)) {
                throw new ParamException("员工" + empInfo.getName() + PF_STR + "重复增员");
            }
        }
    }

    /**
     * 根据子项列表重新计算金额
     */
    private void updateAmountByItemList(List<EmpSocPlanItemUpdateDTO> itemUpdateList, EmpSocPlanUpdateDTO updateDTO,
                                        TokenUser tokenUser) {
        SocProgDO socProgDO = socSchemeService.selectDOById(updateDTO.getSchemeId(), tokenUser.getSiteId());
        boolean onlySocAmount = socProgDO.getOnlySocAmount();
        BigDecimal personalSoc = new BigDecimal("0");
        BigDecimal companySoc = new BigDecimal("0");
        BigDecimal personalPf = new BigDecimal("0");
        BigDecimal companyPf = new BigDecimal("0");
        List<EmpSocPlanItemDO> insertList = new ArrayList<>();
        for (EmpSocPlanItemUpdateDTO empSocPlanItemUpdateDTO : itemUpdateList) {
            BigDecimal cardinalityDefault = empSocPlanItemUpdateDTO.getCardinalityDefault();
            empSocPlanItemUpdateDTO.setPlanId(updateDTO.getId());
            BigDecimal company;
            BigDecimal personal;
            if (onlySocAmount) {
                company = empSocPlanItemUpdateDTO.getAmountCompany();
                personal = empSocPlanItemUpdateDTO.getAmountPersonal();
            } else {
                company = cardinalityDefault.multiply(empSocPlanItemUpdateDTO.getPersentCompany()
                        .multiply(new BigDecimal("0.01")));
                personal = cardinalityDefault.multiply(empSocPlanItemUpdateDTO.getPersentPersonal()
                        .multiply(new BigDecimal("0.01")));
            }
            company = empSocTransformService.mantissaProcessing(company, empSocPlanItemUpdateDTO.getMantissaProcCompany());
            personal = empSocTransformService.mantissaProcessing(personal, empSocPlanItemUpdateDTO.getMantissaProcPersonal());
            empSocPlanItemUpdateDTO.setAmountCompany(company);
            empSocPlanItemUpdateDTO.setAmountPersonal(personal);
            if (SOC_ITEM_TYPE.equals(updateDTO.getType()) ||
                    ME_ITEM_TYPE.equals(updateDTO.getType())) {
                personalSoc = personalSoc.add(personal);
                companySoc = companySoc.add(company);
            } else if (PF_ITEM_TYPE.equals(updateDTO.getType())) {
                personalPf = personalPf.add(personal);
                companyPf = companyPf.add(company);
            } else {
                throw new ParamException("社保子项类型错误");
            }
            EmpSocPlanItemDO insertDO = empSocPlanItemUpdateDTO.to(EmpSocPlanItemDO.class);
            insertDO.setId(null);
            insertDO.preInsert(tokenUser.getUserId());
            insertDO.setSiteId(tokenUser.getSiteId());
            insertList.add(insertDO);
        }
        updateDTO.setPersonalPfAmount(personalPf);
        updateDTO.setPersonalSocAmount(personalSoc);
        updateDTO.setCompanyPfAmount(companyPf);
        updateDTO.setCompanySocAmount(companySoc);
        empSocPlanService.update(updateDTO, tokenUser);
        empSocPlanItemService.bachSave(insertList);
    }

    /**
     * 转换类型
     */
    private String conversionType(Integer type) {
        switch (type) {
            case 1:
                return SOC_STR;
            case 2:
                return PF_STR;
            case 3:
                return ME_STR;
            default:
                throw new ParamException("方案子项类型错误");
        }
    }

    /**
     * 校验增员编辑
     */
    private void checkIncreaseUpdate(String empId, EmpSocPlanDO empSocPlanDO, TokenUser tokenUser) {
        List<EmpSocPlanDO> notFeedback = empSocPlanService
                .findNotFeedback(empId, empSocPlanDO.getType(), INCREASE_STR, tokenUser);
        if (!CollectionUtils.isEmpty(notFeedback)) {
            notFeedback = notFeedback.stream()
                    .filter(plan -> !plan.getId().equals(empSocPlanDO.getId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(notFeedback)) {
                throw new ParamException("重复增员");
            }
        }
    }

    /**
     * 校验减员编辑
     */
    private void checkDecreaseUpdate(String empId, EmpSocPlanDO empSocPlanDO, TokenUser tokenUser) {
        List<EmpSocPlanDO> notFeedback = empSocPlanService
                .findNotFeedback(empId, empSocPlanDO.getType(), DECREASE_STR, tokenUser);
        if (!CollectionUtils.isEmpty(notFeedback)) {
            notFeedback = notFeedback.stream()
                    .filter(plan -> !plan.getId().equals(empSocPlanDO.getId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(notFeedback)) {
                throw new ParamException("重复减员");
            }
        }
    }

}
